#include "spl.includes.h"
#include "splib.h"

using Gdip::PointF;
using Gdip::RectF;
using Gdip::REAL;

void SPLib::Geom::drawImage(
  Gdip::Graphics*     g,
  const  Gdip::Rect   &bounds,
  Gdip::Image*        image,
  ImageSizeMode       sizeMode
  )
{
  switch (sizeMode)
  {
  case ImageSizeModeCenter:
    // draw centered image
    g->DrawImage(
      image,
      bounds.X + (bounds.Width - (INT)image->GetWidth()) / 2,
      bounds.Y + (bounds.Height - (INT)image->GetHeight()) / 2);
    break;
  case ImageSizeModeTile:
    {
      // set horizontal position
      INT x = -bounds.X;
      while (x > 0) x -= image->GetWidth();

      // repeat horizontally
      do
      {
        // set vertical position
        INT y = -bounds.Y;
        while (y > 0) y -= image->GetHeight();

        // repeat vertically
        do
        {
          // draw image
          g->DrawImage(image, x, y);

          // increment vertical position
          y += image->GetHeight();
        }
        while (y < bounds.Height);

        // increment horizontal position
        x += image->GetWidth();
      }
      while (x < bounds.Width);
    }
    break;
  case ImageSizeModeStretch:
    // draw stretched image
    g->DrawImage(image, bounds.X, bounds.Y, bounds.Width, bounds.Height);
    break;
  case ImageSizeModeFit:
  case ImageSizeModeFill:
    {
      // image dimentions
      INT width, height;

      // get image dimentions
      if ((image->GetWidth() > image->GetHeight()) ==
          (sizeMode == ImageSizeModeFit))
      {
        // scale to fit largest side
        width = bounds.Width;
        height = image->GetHeight() * bounds.Width / image->GetWidth();
      }
      else
      {
        // scale to fit smallest side
        width = image->GetWidth() * bounds.Height / image->GetHeight();
        height = bounds.Height;
      }

      // draw scaled image
      g->DrawImage(image,
        bounds.X + (bounds.Width - width) / 2,
        bounds.Y + (bounds.Height - height) / 2,
        width, height);
    }
    break;
  }
}

void SPLib::Geom::getRoundedRect(
  Gdip::GraphicsPath  &path,
  const RectF         &bounds,
  Gdip::REAL          roundness
  )
{
  // arc bounds
  RectF arc(bounds.X, bounds.Y, roundness * 2, roundness * 2);
  // bottom side
  Gdip::REAL bottom = bounds.Y + bounds.Height;
  // right side
  Gdip::REAL right = bounds.X + bounds.Width;

  // construct path
  path.AddArc(arc, 180, 90);
  arc.X += bounds.Width - arc.Width;
  path.AddArc(arc, 270, 90);
  arc.Y += bounds.Height - arc.Height;
  path.AddArc(arc, 0, 90);
  arc.X -= bounds.Width - arc.Width;
  path.AddArc(arc, 90, 90);
  path.CloseFigure();
}

void SPLib::Geom::getRoundedRect(
  Gdip::GraphicsPath  &path,
  const Gdip::Rect    &bounds,
  INT                 roundness
  )
{
  // arc bounds
  Gdip::Rect arc(bounds.X, bounds.Y, roundness * 2, roundness * 2);
  // bottom side
  INT bottom = bounds.Y + bounds.Height;
  // right side
  INT right = bounds.X + bounds.Width;

  // construct path
  path.AddArc(arc, 180, 90);
  arc.X += bounds.Width - arc.Width;
  path.AddArc(arc, 270, 90);
  arc.Y += bounds.Height - arc.Height;
  path.AddArc(arc, 0, 90);
  arc.X -= bounds.Width - arc.Width;
  path.AddArc(arc, 90, 90);
  path.CloseFigure();
}

VOID SPLib::Geom::getHalfRoundedRect(
  Gdip::GraphicsPath  &path,
  const Gdip::RectF   &bounds,
  Gdip::REAL          roundness
  )
{
  // arc bounds
  RectF arc(bounds.X, bounds.Y, roundness * 2, roundness * 2);
  // bottom side
  Gdip::REAL bottom = bounds.Y + bounds.Height;
  // right side
  Gdip::REAL right = bounds.X + bounds.Width;

  // construct path
  path.AddArc(arc, 180, 90);
  arc.X += bounds.Width - arc.Width;
  path.AddArc(arc, 270, 90);
  path.AddLine(right, bottom, bounds.X, bottom);
  path.CloseFigure();
}

VOID SPLib::Geom::getHalfRoundedRect(
  Gdip::GraphicsPath  &path,
  const Gdip::Rect    &bounds,
  INT                 roundness
  )
{
  // arc bounds
  Gdip::Rect arc(bounds.X, bounds.Y, roundness * 2, roundness * 2);
  // bottom side
  INT bottom = bounds.Y + bounds.Height;
  // right side
  INT right = bounds.X + bounds.Width;

  // construct path
  path.AddArc(arc, 180, 90);
  arc.X += bounds.Width - arc.Width;
  path.AddArc(arc, 270, 90);
  path.AddLine(right, bottom, bounds.X, bottom);
  path.CloseFigure();
}

VOID SPLib::Geom::GetUpArrow(
  Gdip::PointF (&oPoints)[POINT_COUNT_ARROW],
  const Gdip::RectF &i
  )
{
  Gdip::REAL wUnit = i.Width / 3.0f;

  oPoints[0] = PointF(i.X, i.Y + (INT)(i.Height / 2.0f));
  oPoints[1] = PointF(i.X + (INT)(i.Width / 2.0f), i.Y);
  oPoints[2] = PointF(i.GetRight(), i.Y + (INT)(i.Height / 2.0f));
  oPoints[3] = PointF(i.X + ceilf(wUnit * 2.0f), i.Y + (INT)(i.Height / 2));
  oPoints[4] = PointF(i.X + ceilf(wUnit * 2.0f), i.GetBottom());
  oPoints[5] = PointF((REAL)(INT)(i.X + wUnit), i.GetBottom());
  oPoints[6] = PointF((REAL)(INT)(i.X + wUnit), i.Y + (INT)(i.Height / 2.0f));
}

VOID SPLib::Geom::GetDownArrow(
  Gdip::PointF (&oPoints)[POINT_COUNT_ARROW],
  const Gdip::RectF &i
  )
{
  Gdip::REAL wUnit = i.Width / 3.0f;

  oPoints[0] = PointF((REAL)(INT)(i.X + wUnit), i.Y);
  oPoints[1] = PointF(i.X + ceilf(wUnit * 2.0f), i.Y);
  oPoints[2] = PointF(i.X + ceilf(wUnit * 2.0f), i.Y + (INT)(i.Height / 2.0f));
  oPoints[3] = PointF(i.GetRight(), i.Y + (INT)(i.Height / 2));
  oPoints[4] = PointF(i.X + (INT)(i.Width / 2.0f), i.GetBottom());
  oPoints[5] = PointF(i.X, i.Y + (INT)(i.Height / 2.0f));
  oPoints[6] = PointF((REAL)(INT)(i.X + wUnit), i.Y + (INT)(i.Height / 2.0f));
}

VOID SPLib::Geom::GetLeftArrow(
  Gdip::PointF (&oPoints)[POINT_COUNT_ARROW],
  const Gdip::RectF &i
  )
{
  Gdip::REAL wUnit = i.Height / 3.0f;

  oPoints[0] = PointF(i.X, i.Y + (REAL)(INT)(i.Height / 2.0f));
  oPoints[1] = PointF(i.X + (INT)(i.Width / 2.0f), i.Y);
  oPoints[2] = PointF(i.X + (INT)(i.Width / 2.0f), (REAL)(INT)(i.Y + wUnit));
  oPoints[3] = PointF(i.GetRight(), (REAL)(INT)(i.Y + wUnit));
  oPoints[4] = PointF(i.GetRight(), i.Y + ceilf(wUnit * 2.0f));
  oPoints[5] = PointF(i.X + (INT)(i.Width / 2.0f), i.Y + ceilf(wUnit * 2.0f));
  oPoints[6] = PointF(i.X + (INT)(i.Width / 2.0f), i.GetBottom());
}

VOID SPLib::Geom::GetRightArrow(
  Gdip::PointF (&oPoints)[POINT_COUNT_ARROW],
  const Gdip::RectF &i
  )
{
  Gdip::REAL wUnit = i.Height / 3.0f;

  oPoints[0] = PointF(i.X, (REAL)(INT)(i.Y + wUnit));
  oPoints[1] = PointF(i.X + (INT)(i.Width / 2.0f), (REAL)(INT)(i.Y + wUnit));
  oPoints[2] = PointF(i.X + (INT)(i.Width / 2.0f), i.Y);
  oPoints[3] = PointF(i.GetRight(), i.Y + (INT)(i.Height / 2.0f));
  oPoints[4] = PointF(i.X + (INT)(i.Width / 2.0f), i.GetBottom());
  oPoints[5] = PointF(i.X + (INT)(i.Width / 2.0f), i.Y + ceilf(wUnit * 2.0f));
  oPoints[6] = PointF(i.X, i.Y + ceilf(wUnit * 2.0f));
}

VOID SPLib::Geom::GetUpTriangle(
  Gdip::PointF (&oPoints)[POINT_COUNT_TRIANGLE],
  const Gdip::RectF &i
  )
{
  PointF* points = new PointF[POINT_COUNT_TRIANGLE];

  oPoints[0] = PointF(i.X, i.Y + i.Height);
  oPoints[1] = PointF(i.X + i.Width / 2.0f, i.Y);
  oPoints[2] = PointF(i.GetRight(), i.Y + i.Height);
}

VOID SPLib::Geom::GetDownTriangle(
  Gdip::PointF (&oPoints)[POINT_COUNT_TRIANGLE],
  const Gdip::RectF &i
  )
{
  oPoints[0] = PointF(i.X, i.Y);
  oPoints[1] = PointF(i.X + i.Width / 2.0f, i.Y + i.Height);
  oPoints[2] = PointF(i.X + i.Width, i.Y);
}

VOID SPLib::Geom::GetLeftTriangle(
  Gdip::PointF (&oPoints)[POINT_COUNT_TRIANGLE],
  const Gdip::RectF &i
  )
{
  oPoints[0] = PointF(i.X + i.Width, i.Y);
  oPoints[1] = PointF(i.X, i.Y + i.Height / 2);
  oPoints[2] = PointF(i.X + i.Width, i.Y + i.Height);
}

VOID SPLib::Geom::GetRightTriangle(
  Gdip::PointF (&oPoints)[POINT_COUNT_TRIANGLE],
  const Gdip::RectF &i
  )
{
  oPoints[0] = PointF(i.X, i.Y);
  oPoints[1] = PointF(i.X + i.Width, i.Y + i.Height / 2.0f);
  oPoints[2] = PointF(i.X, i.Y + i.Height);
}
